#include "timeline.h"
#include <sstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <ctime>
#include <chrono>

// 预设的开始时间
const int start_year = 2019;
const int start_month = 01;

Timeline::Timeline() {
    // 获取今天的日期
    today_ = std::chrono::system_clock::now();

    // 设置起始日期为:
    std::tm tm = {};
    tm.tm_year = start_year - 1900;  // 年份从1900年开始计数
    tm.tm_mon = start_month;             // 月份从0开始计数
    tm.tm_mday = 1;            // 日期从1开始计数
    
    // 转换为time_t
    #ifdef _WIN32
        current_ = std::chrono::system_clock::from_time_t(_mkgmtime(&tm));
    #else
        current_ = std::chrono::system_clock::from_time_t(timegm(&tm));
    #endif
}

std::string Timeline::getCurrentDate() const {
    return timePointToString(current_);
}

std::string Timeline::advanceToNextDay() {
    // 如果已经到达今天，不再前进
    if (hasReachedToday()) {
        return getCurrentDate();
    }

    // 前进一天
    current_ += std::chrono::hours(24);
    
    // 获取新的日期字符串
    std::string newDate = getCurrentDate();

    // 调用所有注册的回调函数
    for (const auto& callback : callbacks_) {
        callback(newDate);
    }
    for (const auto& callback : callbacks_after) {
        callback(newDate);
    }

    return newDate;
}

void Timeline::reset() {
    // 重置为start_year
    std::tm tm = {};
    tm.tm_year = start_year - 1900;
    tm.tm_mon = start_month;
    tm.tm_mday = 1;
    
    #ifdef _WIN32
        current_ = std::chrono::system_clock::from_time_t(_mkgmtime(&tm));
    #else
        current_ = std::chrono::system_clock::from_time_t(timegm(&tm));
    #endif

    // 调用所有注册的回调函数
    std::string currentDate = getCurrentDate();
    for (const auto& callback : callbacks_) {
        callback(currentDate);
    }
    for (const auto& callback : callbacks_after) {
        callback(currentDate);
    }
}

bool Timeline::hasReachedToday() const {
    // 将两个时间点转换为天数进行比较
    auto today_days = std::chrono::duration_cast<std::chrono::hours>(today_.time_since_epoch()).count() / 24;
    auto current_days = std::chrono::duration_cast<std::chrono::hours>(current_.time_since_epoch()).count() / 24;
    return current_days >= today_days;
}

void Timeline::registerCallback(Callback callback) {
    callbacks_.push_back(std::move(callback));
}

void Timeline::registerCallback_after(Callback callback) {
    callbacks_after.push_back(std::move(callback));
}

std::string Timeline::timePointToString(const TimePoint& tp) const {
    auto time_t = std::chrono::system_clock::to_time_t(tp);
    std::tm tm = {};
    
    #ifdef _WIN32
        gmtime_s(&tm, &time_t);
    #else
        gmtime_r(&time_t, &tm);
    #endif

    std::stringstream ss;
    ss << std::put_time(&tm, "%Y-%m-%d");
    return ss.str();
} 

// 设置日期
void Timeline::setDate(const std::string& date)
{
    std::tm tm = {};
    std::istringstream ss(date);
    ss >> std::get_time(&tm, "%Y-%m-%d");
    if (ss.fail()) {
        std::cerr << "Invalid date format. Expected format: YYYY-MM-DD" << std::endl;
        return;
    }

    // 转换为time_t
    #ifdef _WIN32
        current_ = std::chrono::system_clock::from_time_t(_mkgmtime(&tm));
    #else
        current_ = std::chrono::system_clock::from_time_t(timegm(&tm));
    #endif
    
    // 调用所有注册的回调函数
    for (const auto& callback : callbacks_) {
        callback(date);
    }
    for (const auto& callback : callbacks_after) {
        callback(date);
    }
}



// Function to convert a date string (YYYY-MM-DD) to a std::tm structure
std::tm stringToTm(const std::string& dateStr) {
    std::tm tm = {};
    std::istringstream ss(dateStr);
    ss >> std::get_time(&tm, "%Y-%m-%d");
    if (ss.fail()) {
        throw std::runtime_error("Invalid date format");
    }
    return tm;
}

// Function to convert a std::tm structure to a date string (YYYY-MM-DD)
std::string tmToString(const std::tm& tm) {
    std::ostringstream ss;
    ss << std::put_time(&tm, "%Y-%m-%d");
    return ss.str();
}


// 取N天前的时间
std::string Timeline::getNDaysAgo(const std::string &date,int n)
{
    // Convert the date string to a std::tm structure
    std::tm tm = stringToTm(date);

    // Convert the std::tm structure to a time_t
    std::time_t time = std::mktime(&tm);
    if (time == -1) {
        throw std::runtime_error("Invalid date");
    }

    // Convert the time_t to a std::chrono::system_clock::time_point
    std::chrono::system_clock::time_point tp = std::chrono::system_clock::from_time_t(time);

    // Subtract 90 days
    tp -= std::chrono::days(n);

    // Convert the resulting time_point back to a time_t
    time = std::chrono::system_clock::to_time_t(tp);

    // Convert the time_t back to a std::tm structure
    tm = *std::localtime(&time);

    // Convert the std::tm structure back to a date string
    return tmToString(tm);
}

/*
对话记录:
做一个时间线管理模块, 能从2020年一月一日一天一天加到今天, 提供获取时间状态的接口, 提供推进到下一天的接口,不显示时分秒, 只显示日期. 
别再帮我改CMakeLists.txt代码, CMakeLists让我自己改.
做这个模块的目的是提供一个信号源,用于通知其它模块进行下一步运算. 
 */